home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
gofer221.zip
/
TYPE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
61KB
|
1,883 lines
/* --------------------------------------------------------------------------
* type.c: Copyright (c) Mark P Jones 1991. All rights reserved.
* See goferite.h for details and conditions of use etc...
* Gofer version 2.21 November 1991
*
* Last updated 11/11/91 mpj
*
* This is the gofer type checker: Based on the extended algorithm in my
* PRG technical report PRG-TR-10-91, supporting the use of qualified types
* in the form of multi-parameter type classes, according to my `new
* approach' to type classes posted to the Haskell mailing list.
* This program uses the optimisations for constant and locally-constant
* overloading.
* ------------------------------------------------------------------------*/
#include "prelude.h"
#include "storage.h"
#include "connect.h"
#include "errors.h"
Bool coerceNumLiterals = FALSE; /* TRUE => insert fromInteger calls*/
/* etc for numeric literals*/
Bool catchAmbigs = FALSE; /* TRUE => functions with ambig. */
/* types produce error */
Type typeString, typeDialogue; /* String & Dialogue types */
Name nameTrue, nameFalse; /* primitive boolean constructors */
Name nameNil, nameCons; /* primitive list constructors */
/* --------------------------------------------------------------------------
* Data structures for storing a substitution:
*
* For various reasons, this implementation uses structure sharing, instead of
* a copying approach. In principal, this is fast and avoids the need to
* build new type expressions. Unfortunately, this implementation will not
* be able to handle *very* large expressions.
*
* The substitution is represented by an array of type variables each of
* which is a pair:
* bound a (skeletal) type expression, or NIL if the variable
* is not bound.
* offs offset of skeleton in bound. If isNull(bound), then offs is
* used to indicate whether that variable is generic (i.e. free
* in the current assumption set) or fixed (i.e. bound in the
* current assumption set). Generic variables are assigned
* offset numbers whilst copying type expressions (t,o) to
* obtain their most general form.
* ------------------------------------------------------------------------*/
typedef struct { /* Each type variable contains: */
Type bound; /* A type skeleton (unbound==NIL) */
Int offs; /* Offset for skeleton */
} Tyvar;
static Int numTyvars; /* no. type vars currently in use */
static Tyvar tyvars[NUM_TYVARS]; /* storage for type variables */
static Int typeOff; /* offset of result type */
static Type typeIs; /* skeleton of result type */
static List predsAre; /* list of predicates in type */
#define tyvar(n) (tyvars+(n)) /* nth type variable */
#define tyvNum(t) ((t)-tyvars) /* and the corresp. inverse funct. */
static Int nextGeneric; /* number of generics found so far */
/* offs values when isNull(bound): */
#define FIXED_TYVAR 0 /* fixed in current assumption */
#define UNUSED_GENERIC 1 /* not fixed, not yet encountered */
#define GENERIC 2 /* GENERIC+n==nth generic var found*/
/* --------------------------------------------------------------------------
* Local function prototypes:
* ------------------------------------------------------------------------*/
static Void local emptySubstitution Args((Void));
static Int local newTyvars Args((Int));
static Tyvar *local getTypeVar Args((Type,Int));
static Void local tyvarType Args((Int));
static Void local bind Args((Int,Type,Int));
static Void local expandSynonym Args((Tycon, Type *, Int *));
static Void local clearMarks Args((Void));
static Void local resetGenericsFrom Args((Int));
static Void local markTyvar Args((Int));
static Void local markType Args((Type,Int));
static Type local copyTyvar Args((Int));
static Type local copyType Args((Type,Int));
static Bool local doesntOccurIn Args((Type,Int));
static Bool local varToVarBind Args((Tyvar *,Tyvar *));
static Bool local varToTypeBind Args((Tyvar *,Type,Int));
static Bool local unify Args((Type,Int,Type,Int));
static Bool local sameType Args((Type,Int,Type,Int));
static Void local emptyAssumption Args((Void));
static Void local enterBindings Args((Void));
static Void local leaveBindings Args((Void));
static Void local markAssumList Args((List));
static Cell local findAssum Args((Text));
static Pair local findInAssumList Args((Text,List));
static Int local newVarsBind Args((Cell));
static Void local newDefnBind Args((Cell,Type));
static Void local instantiate Args((Type));
static Void local typeError Args((Int,Cell,Cell,String,Type,Int));
static Cell local typeExpr Args((Int,Cell));
static Cell local varIntro Args((Cell,Type));
static Void local typeEsign Args((Int,Cell));
static Void local typeCase Args((Int,Int,Cell));
static Void local typeQualifier Args((Int,Cell));
static Cell local typeFreshPat Args((Int,Cell));
static Cell local typeAp Args((Int,Cell));
static Void local typeAlt Args((Cell));
static Int local funcType Args((Int));
static Void local typeTuple Args((Cell));
static Type local makeTupleType Args((Int));
static Void local typeBindings Args((List));
static Void local removeTypeSigs Args((Cell));
static Void local noOverloading Args((List));
static Void local restrictedBindAss Args((Cell));
static Void local restrictedAss Args((Int,Cell,Type));
static Void local explicitTyping Args((List));
static List local gotoExplicit Args((List));
static List local explPreds Args((Text,List,List));
static Void local implicitTyping Args((List));
static Void local addEvidParams Args((List,Cell));
static Void local typeInstDefn Args((Inst));
static Void local typeClassDefn Args((Class));
static Void local typeMembers Args((String,List,List,Cell,Int));
static Void local typeMember Args((String,Name,Name,Cell,Int));
static Void local typeBind Args((Cell));
static Void local typeDefAlt Args((Int,Cell,Pair));
static Cell local typeRhs Args((Cell));
static Void local guardedType Args((Int,Cell));
static Void local generaliseBind Args((Int,List,Cell));
static Void local generaliseAss Args((Int,List,Cell));
static Type local generalise Args((List,Type));
static Void local checkBindSigs Args((Cell));
static Void local checkTypeSig Args((Int,Cell,Type));
static Void local tooGeneral Args((Int,Cell,Type,Type));
static Bool local equalSchemes Args((Type,Type));
static Bool local equalQuals Args((List,List));
static Bool local equalTypes Args((Type,Type));
static Void local typeDefnGroup Args((List));
/* --------------------------------------------------------------------------
* Frequently used type skeletons:
* ------------------------------------------------------------------------*/
static Type var; /* mkOffset(0) */
static Type arrow; /* mkOffset(0) -> mkOffset(1) */
static Type typeList; /* [ mkOffset(0) ] */
static Type typeBool; /* Bool */
static Type typeInt; /* Int (or Num) */
static Type typeFloat; /* Float */
static Type typeUnit; /* () */
static Type typeChar; /* Char */
static Type typeIntToInt; /* Int -> Int */
static Name nameFromInt; /* fromInteger function */
static Class classNum; /* class Num */
static Cell predNum; /* Num (mkOffset(0)) */
/* --------------------------------------------------------------------------
* Basic operations on current substitution:
* ------------------------------------------------------------------------*/
static Void local emptySubstitution() { /* clear current substitution */
numTyvars = 0;
nextGeneric = 0;
typeIs = NIL;
predsAre = NIL;
}
static Int local newTyvars(n) /* allocate new type variables */
Int n; {
Int beta = numTyvars;
if (numTyvars+n>NUM_TYVARS) {
ERROR(0) "Too many type variables in type checker"
EEND;
}
for (numTyvars+=n; n>0; n--) {
tyvars[numTyvars-n].offs = UNUSED_GENERIC;
tyvars[numTyvars-n].bound = NIL;
}
return beta;
}
#define freeTypeVars(beta) numTyvars=beta
#define deRef(tyv,t,o) while ((tyv=getTypeVar(t,o)) && tyv->bound) { \
t = tyv->bound; \
o = tyv->offs; \
}
static Tyvar *local getTypeVar(t,o) /* get number of type variable */
Type t; /* represented by (t,o) [if any]. */
Int o; {
switch (whatIs(t)) {
case INTCELL : return tyvar(intOf(t));
case OFFSET : return tyvar(o+offsetOf(t));
}
return ((Tyvar *)0);
}
static Void local tyvarType(vn) /* load type held in type variable */
Int vn; { /* vn into (typeIs,typeOff) */
Tyvar *tyv;
while ((tyv=tyvar(vn))->bound)
switch(whatIs(tyv->bound)) {
case INTCELL : vn = intOf(tyv->bound);
break;
case OFFSET : vn = offsetOf(tyv->bound)+(tyv->offs);
break;
default : typeIs = tyv->bound;
typeOff = tyv->offs;
return;
}
typeIs = var;
typeOff = vn;
}
static Void local bind(vn,t,o) /* set type variable vn to (t,o) */
Int vn;
Type t;
Int o; {
Tyvar *tyv = tyvar(vn);
tyv->bound = t;
tyv->offs = o;
}
static Void local expandSynonym(h,at,ao)/* Expand type synonym with head h */
Tycon h; /* original expression (*at,*ao) */
Type *at; /* expansion returned in (*at,*ao) */
Int *ao; {
Int n = tycon(h).arity;
Type t = *at;
Int o = *ao;
*at = tycon(h).defn;
*ao = newTyvars(n);
for (; 0<n--; t=fun(t))
bind(*ao+n,arg(t),o);
}
/* --------------------------------------------------------------------------
* Mark type expression, so that all variables are marked as unused generics
* ------------------------------------------------------------------------*/
static Void local clearMarks() { /* set all unbound type vars to */
Int i; /* unused generic variables */
for (i=0; i<numTyvars; ++i)
if (isNull(tyvars[i].bound))
tyvars[i].offs = UNUSED_GENERIC;
nextGeneric = 0;
}
static Void local resetGenericsFrom(n) /* reset all generic vars to unused*/
Int n; { /* for generics >= n */
Int i;
for (i=0; i<numTyvars; ++i)
if (isNull(tyvars[i].bound) && tyvars[i].offs>=GENERIC+n)
tyvars[i].offs = UNUSED_GENERIC;
nextGeneric = n;
}
static Void local markTyvar(vn) /* mark fixed vars in type bound to*/
Int vn; { /* given type variable */
Tyvar *tyv = tyvar(vn);
if (tyv->bound)
markType(tyv->bound, tyv->offs);
else
(tyv->offs) = FIXED_TYVAR;
}
static Void local markType(t,o) /* mark fixed vars in type (t,o) */
Type t;
Int o; {
switch (whatIs(t)) {
case TYCON :
case TUPLE :
case UNIT :
case ARROW :
case LIST : return;
case AP : markType(fst(t),o);
markType(snd(t),o);
return;
case OFFSET : markTyvar(o+offsetOf(t));
return;
case INTCELL : markTyvar(intOf(t));
return;
default : internal("markType");
}
}
/* --------------------------------------------------------------------------
* Copy type expression from substitution to make a single type expression:
* ------------------------------------------------------------------------*/
static Type local copyTyvar(vn) /* calculate most general form of */
Int vn; { /* type bound to given type var */
Tyvar *tyv = tyvar(vn);
if (tyv->bound)
return copyType(tyv->bound,tyv->offs);
switch (tyv->offs) {
case FIXED_TYVAR : return mkInt(vn);
case UNUSED_GENERIC : (tyv->offs) = GENERIC + nextGeneric++;
default : return mkOffset(tyv->offs - GENERIC);
}
}
static Type local copyType(t,o) /* calculate most general form of */
Type t; /* type expression (t,o) */
Int o; {
switch (whatIs(t)) {
case AP : { Type l = copyType(fst(t),o); /* ensure correct */
Type r = copyType(snd(t),o); /* eval. order */
return ap(l,r);
}
case OFFSET : return copyTyvar(o+offsetOf(t));
case INTCELL : return copyTyvar(intOf(t));
}
return t;
}
/* --------------------------------------------------------------------------
* Occurs check:
* ------------------------------------------------------------------------*/
static Tyvar *lookingFor; /* var to look for in occurs check */
static Bool local doesntOccurIn(t,o) /* Return TRUE if var lookingFor */
Type t; /* isn't referenced in (t,o) */
Int o; {
Tyvar *tyv;
deRef(tyv,t,o);
if (tyv) /* type variable */
return tyv!=lookingFor;
if (isAp(t)) { /* type constructor with args */
Type t1 = t;
do {
if (doesntOccurIn(snd(t1),o))
t1 = fst(t1);
else
return FALSE;
} while (isAp(t1));
}
return TRUE; /* variable was not found */
}
/* --------------------------------------------------------------------------
* Unification algorithm:
* ------------------------------------------------------------------------*/
static matchMode = FALSE; /* set to TRUE to prevent binding */
/* during matching process */
static Bool local varToVarBind(tyv1,tyv2)/* Make binding tyv1 := tyv2 */
Tyvar *tyv1, *tyv2; {
if (tyv1!=tyv2)
if (matchMode)
return FALSE;
else {
tyv1->bound = var;
tyv1->offs = tyvNum(tyv2);
}
return TRUE;
}
static Bool local varToTypeBind(tyv,t,o)/* Make binding tyv := (t,o) */
Tyvar *tyv;
Type t; /* guaranteed not to be a v'ble or */
Int o; { /* have synonym as outermost constr*/
if (!matchMode) {
lookingFor = tyv;
if (doesntOccurIn(t,o)) {
tyv->bound = t;
tyv->offs = o;
return TRUE;
}
}
return FALSE; /* INFINITE TYPE (or failed match in matchMode) */
}
static Bool local unify(t1,o1,t2,o2) /* Main unification routine */
Type t1,t2; /* unify (t1,o1) with (t2,o2) */
Int o1,o2; {
Tyvar *tyv1, *tyv2;
deRef(tyv1,t1,o1);
deRef(tyv2,t2,o2);
un: if (tyv1)
if (tyv2)
return varToVarBind(tyv1,tyv2); /* t1, t2 variables */
else {
Cell h2 = getHead(t2);
if (isSynonym(h2)) {
expandSynonym(h2,&t2,&o2);
deRef(tyv2,t2,o2);
goto un;
}
return varToTypeBind(tyv1,t2,o2); /* t1 variable, t2 not */
}
else
if (tyv2) {
Cell h1 = getHead(t1);
if (isSynonym(h1)) {
expandSynonym(h1,&t1,&o1);
deRef(tyv1,t1,o1);
goto un;
}
return varToTypeBind(tyv2,t1,o1); /* t2 variable, t1 not */
}
else { /* t1, t2 not vars */
Type h1 = getHead(t1);
Type h2 = getHead(t2);
if (h1==h2) { /* Assuming well-formed types, both*/
while (isAp(t1)) { /* t1, t2 must have same no of args*/
if (!unify(arg(t1),o1,arg(t2),o2))
return FALSE;
t1 = fun(t1);
t2 = fun(t2);
}
return TRUE;
}
/* Types do not match -- look for type synonyms to expand */
if (isSynonym(h1)) {
expandSynonym(h1,&t1,&o1);
deRef(tyv1,t1,o1);
goto un;
}
if (isSynonym(h2)) {
expandSynonym(h2,&t2,&o2);
deRef(tyv2,t2,o2);
goto un;
}
}
return FALSE;
}
static Bool local sameType(t1,o1,t2,o2)/* Compare types without binding */
Type t1,t2;
Int o1,o2; {
Bool result;
matchMode = TRUE;
result = unify(t1,o1,t2,o2);
matchMode = FALSE;
return result;
}
Bool typeMatches(type,mt) /* test if type matches monotype mt*/
Type type, mt; {
Bool result;
if (isPolyType(type) || whatIs(type)==QUAL)
return FALSE;
typeChecker(RESET);
matchMode = TRUE;
result = unify(mt,0,type,0);
matchMode = FALSE;
typeChecker(RESET);
return result;
}
/* --------------------------------------------------------------------------
* Assumptions:
*
* A basic typing statement is a pair (Var,Type) and an assumption contains
* an ordered list of basic typing statements in which the type for a given
* variable is given by the most recently added assumption about that var.
*
* In practice, the assumption set is split between a pair of lists, one
* holding assumptions for vars defined in bindings, the other for vars
* defined in patterns/binding parameters etc. The reason for this
* separation is that vars defined in bindings may be overloaded (with the
* overloading being unknown until the whole binding is typed), whereas the
* vars defined in patterns have no overloading. A form of dependency
* analysis (at least as far as calculating dependents within the same group
* of value bindings) is required to implement this. Where it is known that
* no overloaded values are defined in a binding (i.e. when the `dreaded
* monomorphism restriction' strikes), the list used to record dependents
* is flagged with a NODEPENDS tag to avoid gathering dependents at that
* level.
*
* To interleave between vars for bindings and vars for patterns, we use
* a list of lists of typing statements for each. These lists are always
* the same length. The implementation here is very similar to that of the
* dependency analysis used in the static analysis component of this system.
* ------------------------------------------------------------------------*/
static List defnBounds; /*::[[(Var,Type)]] possibly ovrlded*/
static List varsBounds; /*::[[(Var,Type)]] not overloaded */
static List depends; /*::[?[Var]] dependents/NODEPENDS */
#define saveVarsAssump() List saveAssump = hd(varsBounds)
#define restoreVarsAss() hd(varsBounds) = saveAssump
static Void local emptyAssumption() { /* set empty type assumption */
defnBounds = NIL;
varsBounds = NIL;
depends = NIL;
}
static Void local enterBindings() { /* Add new level to assumption sets */
defnBounds = cons(NIL,defnBounds);
varsBounds = cons(NIL,varsBounds);
depends = cons(NIL,depends);
}
static Void local leaveBindings() { /* Drop one level of assumptions */
defnBounds = tl(defnBounds);
varsBounds = tl(varsBounds);
depends = tl(depends);
}
static Void local markAssumList(as) /* Mark all types in assumption set */
List as; { /* :: [(Var, Type)] */
for (; nonNull(as); as=tl(as)) /* No need to mark generic types; */
if (!isPolyType(snd(hd(as)))) /* the only free variables in those */
markType(snd(hd(as)),0); /* must have been free earlier too */
}
static Cell local findAssum(t) /* Find most recent assumption about*/
Text t; { /* variable named t, if any */
List defnBounds1 = defnBounds; /* return translated variable, with */
List varsBounds1 = varsBounds; /* type in typeIs */
List depends1 = depends;
while (nonNull(defnBounds1)) {
Pair ass = findInAssumList(t,hd(varsBounds1));/* search varsBounds */
if (nonNull(ass)) {
typeIs = snd(ass);
return fst(ass);
}
ass = findInAssumList(t,hd(defnBounds1)); /* search defnBounds */
if (nonNull(ass)) {
Cell v = fst(ass);
typeIs = snd(ass);
if (hd(depends1)!=NODEPENDS && /* save dependent? */
isNull(v=varIsMember(t,hd(depends1))))
/* N.B. make new copy of variable and store this on list of*/
/* dependents, and in the assumption so that all uses of */
/* the variable will be at the same node, if we need to */
/* overwrite the call of a function with a translation... */
hd(depends1) = cons(v=mkVar(t),hd(depends1));
return v;
}
defnBounds1 = tl(defnBounds1); /* look in next level*/
varsBounds1 = tl(varsBounds1); /* of assumption set */
depends1 = tl(depends1);
}
return NIL;
}
static Pair local findInAssumList(t,as)/* Search for assumption for var */
Text t; /* named t in list of assumptions as*/
List as; {
for (; nonNull(as); as=tl(as))
if (textOf(fst(hd(as)))==t)
return hd(as);
return NIL;
}
#define findTopBinding(v) findInAssumList(textOf(v),hd(defnBounds))
static Int local newVarsBind(v) /* make new assump for pattern var */
Cell v; {
Int beta = newTyvars(1);
hd(varsBounds) = cons(pair(v,mkInt(beta)), hd(varsBounds));
return beta;
}
static Void local newDefnBind(v,type) /* make new assump for defn var */
Cell v; /* and set type if given (nonNull) */
Type type; {
Int beta = newTyvars(1);
hd(defnBounds) = cons(pair(v,mkInt(beta)), hd(defnBounds));
instantiate(type);
bind(beta,typeIs,typeOff); /* Bind beta to new type skeleton */
}
static Void local instantiate(type) /* instantiate type expr, if nonNull*/
Type type; {
predsAre = NIL;
typeIs = type;
typeOff = 0;
if (nonNull(typeIs)) { /* instantiate type expression ? */
if (isPolyType(typeIs)) { /* Polymorphic type scheme ? */
typeOff = newTyvars(intOf(fst(typeIs)));
typeIs = snd(typeIs);
}
if (whatIs(typeIs)==QUAL) { /* Qualified type? */
predsAre = fst(snd(typeIs));
typeIs = snd(snd(typeIs));
}
}
}
/* --------------------------------------------------------------------------
* Predicate sets:
*
* A predicate set is represented by a list of triples (C t, o, used)
* which indicates that type (t,o) must be an instance of class C, with
* evidence required at the node pointed to by used. Note that the `used'
* node may need to be overwritten at a later stage if this evidence is
* to be derived from some other predicates by entailment.
* ------------------------------------------------------------------------*/
#include "preds.c"
/* --------------------------------------------------------------------------
* Type errors:
* ------------------------------------------------------------------------*/
static Void local typeError(l,e,in,wh,t,o)
Int l; /* line number near type error */
String wh; /* place in which error occurs */
Cell e; /* source of error */
Cell in; /* context if any (NIL if not) */
Type t; /* should be of type (t,o) */
Int o; { /* type inferred is (typeIs,typeOff) */
clearMarks(); /* types printed here are monotypes */
/* use marking to give sensible names*/
ERROR(l) "Type error in %s", wh ETHEN
if (nonNull(in)) {
ERRTEXT "\n*** expression : " ETHEN ERREXPR(in);
}
ERRTEXT "\n*** term : " ETHEN ERREXPR(e);
ERRTEXT "\n*** type : " ETHEN ERRTYPE(copyType(typeIs,typeOff));
ERRTEXT "\n*** does not match : " ETHEN ERRTYPE(copyType(t,o));
ERRTEXT "\n"
EEND;
}
#define shouldBe(l,e,in,where,t,o) if (!unify(typeIs,typeOff,t,o)) \
typeError(l,e,in,where,t,o);
#define check(l,e,in,where,t,o) e=typeExpr(l,e); shouldBe(l,e,in,where,t,o)
#define inferType(t,o) typeIs=t; typeOff=o
/* --------------------------------------------------------------------------
* Typing of expressions:
* ------------------------------------------------------------------------*/
static patternMode = FALSE; /* set to TRUE to type check pattern*/
static Cell local typeExpr(l,e) /* Determine type of expr/pattern */
Int l;
Cell e; {
static String cond = "conditional";
static String list = "list";
static String listComp = "list comprehension";
static String discr = "case discriminant";
switch (whatIs(e)) {
/* The following cases can occur in either pattern or expr. mode */
case AP : return typeAp(l,e);
case NAME : if (isNull(name(e).type))
internal("typeExpr1");
return varIntro(e,name(e).type);
case TUPLE : typeTuple(e);
break;
case INTCELL : if (!patternMode && coerceNumLiterals) {
Int alpha = newTyvars(1);
inferType(var,alpha);
return ap(ap(nameFromInt,
assumeEvid(predNum,alpha)),
e);
}
else {
inferType(typeInt,0);
}
break;
case FLOATCELL : inferType(typeFloat,0);
break;
case STRCELL : inferType(typeString,0);
break;
case UNIT : inferType(typeUnit,0);
break;
case CHARCELL : inferType(typeChar,0);
break;
case VAROPCELL :
case VARIDCELL : if (patternMode) {
inferType(var,newVarsBind(e));
}
else {
Cell a = findAssum(textOf(e));
if (nonNull(a))
return varIntro(a,typeIs);
else {
a = findName(textOf(e));
if (isNull(a) || isNull(name(a).type))
internal("typeExpr2");
return varIntro(a,name(a).type);
}
}
break;
/* The following cases can only occur in expr mode */
case COND : { Int beta = newTyvars(1);
check(l,fst3(snd(e)),e,cond,typeBool,0);
check(l,snd3(snd(e)),e,cond,var,beta);
check(l,thd3(snd(e)),e,cond,var,beta);
tyvarType(beta);
}
break;
case FINLIST : { Int beta = newTyvars(1);
List xs;
for (xs=snd(e); nonNull(xs); xs=tl(xs)) {
check(l,hd(xs),e,list,var,beta);
}
inferType(typeList,beta);
}
break;
case LETREC : enterBindings();
mapProc(typeBindings,fst(snd(e)));
snd(snd(e)) = typeExpr(l,snd(snd(e)));
leaveBindings();
break;
case LISTCOMP : { Int beta = newTyvars(1);
saveVarsAssump();
map1Proc(typeQualifier,l,snd(snd(e)));
check(l,fst(snd(e)),NIL,listComp,var,beta);
inferType(typeList,beta);
restoreVarsAss();
}
break;
case ESIGN : typeEsign(l,e);
return fst(snd(e));
case CASE : { Int beta = newTyvars(2); /* discr result */
check(l,fst(snd(e)),NIL,discr,var,beta);
map2Proc(typeCase,l,beta,snd(snd(e)));
tyvarType(beta+1);
}
break;
case LAMBDA : typeAlt(snd(e));
break;
/* The remaining cases can only occur in pattern mode: */
case WILDCARD : inferType(var,newTyvars(1));
break;
case ASPAT : snd(snd(e)) = typeExpr(l,snd(snd(e)));
bind(newVarsBind(fst(snd(e))),typeIs,typeOff);
break;
case LAZYPAT : snd(e) = typeExpr(l,snd(e));
break;
case ADDPAT :
case MULPAT : inferType(typeIntToInt,0);
break;
default : internal("typeExpr3");
}
return e;
}
static Cell local varIntro(v,type) /* make translation of var v with */
Cell v; /* given type adding any extra dict */
Type type; { /* params required */
/* N.B. In practice, v will either be a NAME or a VARID/OPCELL */
for (instantiate(type); nonNull(predsAre); predsAre=tl(predsAre))
v = ap(v,assumeEvid(hd(predsAre),typeOff));
return v;
}
static Void local typeEsign(l,e) /* Type check expression type sig */
Int l;
Cell e; {
static String typeSig = "type signature expression";
List savePreds = preds;
Int alpha = newTyvars(1);
List expPreds; /* explicit preds in type sig */
List qs; /* qualifying preds in infered type*/
Type nt; /* complete infered type */
preds = NIL;
instantiate(snd(snd(e)));
bind(alpha,typeIs,typeOff);
expPreds = makeEvidArgs(predsAre,typeOff);
check(l,fst(snd(e)),NIL,typeSig,var,alpha);
clearMarks();
mapProc(markAssumList,defnBounds);
mapProc(markAssumList,varsBounds);
mapProc(markPred,savePreds);
savePreds = elimConstPreds(l,typeSig,e,savePreds);
explicitProve(l,typeSig,fst(snd(e)),expPreds,preds);
resetGenericsFrom(0);
qs = copyPreds(expPreds);
nt = generalise(qs,copyTyvar(alpha));
if (!equalSchemes(nt,snd(snd(e))))
tooGeneral(l,fst(snd(e)),snd(snd(e)),nt);
tyvarType(alpha);
preds = revOnto(expPreds,savePreds);
}
static Void local typeCase(l,beta,c) /* type check case: pat -> rhs */
Int l; /* (case given by c == (pat,rhs)) */
Int beta; /* need: pat :: (var,beta) */
Cell c; { /* rhs :: (var,beta+1) */
static String casePat = "case pattern";
static String caseExpr = "case expression";
saveVarsAssump();
fst(c) = typeFreshPat(l,fst(c));
shouldBe(l,fst(c),NIL,casePat,var,beta);
snd(c) = typeRhs(snd(c));
shouldBe(l,rhsExpr(snd(c)),NIL,caseExpr,var,beta+1);
restoreVarsAss();
}
static Void local typeQualifier(l,q) /* type check qualifier in list comp*/
Int l;
Cell q; {
static String boolQual = "boolean qualifier";
static String genQual = "generator";
static String defnQual = "qualifier definition";
switch (whatIs(q)) {
case BOOLQUAL : check(l,snd(q),NIL,boolQual,typeBool,0);
break;
case QWHERE : { Int beta = newTyvars(1);
fst(snd(q)) = typeFreshPat(l,fst(snd(q)));
bind(beta,typeIs,typeOff);
check(l,snd(snd(q)),NIL,defnQual,var,beta);
}
break;
case FROMQUAL : { Int beta = newTyvars(1);
check(l,snd(snd(q)),NIL,genQual,typeList,beta);
fst(snd(q)) = typeFreshPat(l,fst(snd(q)));
shouldBe(l,fst(snd(q)),NIL,genQual,var,beta);
}
break;
}
}
static Cell local typeFreshPat(l,p) /* find type of pattern, assigning */
Int l; /* fresh type variables to each var */
Cell p; { /* bound in the pattern */
patternMode = TRUE;
p = typeExpr(l,p);
patternMode = FALSE;
return p;
}
/* --------------------------------------------------------------------------
* Note the pleasing duality in the typing of application and abstraction:-)
* ------------------------------------------------------------------------*/
static Cell local typeAp(l,e) /* Type check application */
Int l;
Cell e; {
static String app = "application";
Cell h = getHead(e); /* e = h e1 e2 ... en */
Int n = argCount; /* save no. of arguments */
Int beta = funcType(n);
Cell p = NIL; /* points to previous AP node */
Cell a = e; /* points to current AP node */
Int i;
check(l,h,e,app,var,beta); /* check h::t1->t2->...->tn->rn+1 */
for (i=n; i>0; --i) { /* check e_i::t_i for each i */
check(l,arg(a),e,app,var,beta+2*i-1);
p = a;
a = fun(a);
}
fun(p) = h; /* replace head with translation */
tyvarType(beta+2*n); /* inferred type is r_n+1 */
return e;
}
static Void local typeAlt(a) /* Type check abstraction (Alt) */
Cell a; { /* a = ( [p1, ..., pn], rhs ) */
List ps = fst(a);
Int n = length(ps);
Int beta = funcType(n);
Int l = rhsLine(snd(a));
Int i;
saveVarsAssump();
for (i=0; i<n; ++i) {
hd(ps) = typeFreshPat(l,hd(ps));
bind(beta+2*i+1,typeIs,typeOff);
ps = tl(ps);
}
snd(a) = typeRhs(snd(a));
bind(beta+2*n,typeIs,typeOff);
tyvarType(beta);
restoreVarsAss();
}
static Int local funcType(n) /*return skeleton for function type*/
Int n; { /*with n arguments, taking the form*/
Int beta = newTyvars(2*n+1); /* r1 t1 r2 t2 ... rn tn rn+1 */
Int i; /* with r_i := t_i -> r_i+1 */
for (i=0; i<n; ++i)
bind(beta+2*i,arrow,beta+2*i+1);
return beta;
}
/* --------------------------------------------------------------------------
* Tuple type constructors: are generated as necessary. The most common
* n-tuple constructors (n<MAXTUPCON) are held in a cache to avoid
* repeated generation of the constructor types.
*
* ???Maybe this cache should extend to all valid tuple constrs???
* ------------------------------------------------------------------------*/
#define MAXTUPCON 10
static Type tupleConTypes[MAXTUPCON];
static Void local typeTuple(e) /* find type for tuple constr, using*/
Cell e; { /* tupleConTypes to cache previously*/
Int n = tupleOf(e); /* calculated tuple constr. types. */
typeOff = newTyvars(n);
if (n>=MAXTUPCON)
typeIs = makeTupleType(n);
else if (tupleConTypes[n])
typeIs = tupleConTypes[n];
else
typeIs = tupleConTypes[n] = makeTupleType(n);
}
static Type local makeTupleType(n) /* construct type for tuple constr. */
Int n; { /* t1 -> ... -> tn -> (t1,...,tn) */
Type h = mkTuple(n);
Int i;
for (i=0; i<n; ++i)
h = ap(h,mkOffset(i));
while (0<n--)
h = fn(mkOffset(n),h);
return h;
}
/* --------------------------------------------------------------------------
* Type check group of bindings:
* ------------------------------------------------------------------------*/
static Void local typeBindings(bs) /* type check a single binding group*/
List bs; {
Bool usesPatternBindings = FALSE;
Bool usesSimplePatterns = FALSE;
Bool usesTypeSigs = FALSE;
List bs1;
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) { /* Analyse binding group */
Cell b = hd(bs1);
if (!isVar(fst(b)))
usesPatternBindings = TRUE;
else if (isNull(fst(hd(snd(snd(b))))))
usesSimplePatterns = TRUE;
if (nonNull(fst(snd(b)))) /* any explicitly typed */
usesTypeSigs = TRUE; /* bindings in group? */
}
hd(defnBounds) = NIL;
hd(depends) = NIL;
if (usesPatternBindings || (usesSimplePatterns && !usesTypeSigs))
noOverloading(bs);
else if (usesTypeSigs)
explicitTyping(bs);
else
implicitTyping(bs);
mapProc(checkBindSigs,bs); /* compare with sig decls */
mapProc(removeTypeSigs,bs); /* Remove binding type info */
hd(varsBounds) = revOnto(hd(defnBounds), /* transfer completed assmps*/
hd(varsBounds)); /* out of defnBounds */
hd(defnBounds) = NIL;
hd(depends) = NIL;
}
static Void local removeTypeSigs(b) /* Remove type info from a binding */
Cell b; {
snd(b) = snd(snd(b));
}
/* --------------------------------------------------------------------------
* Restricted binding group:
* ------------------------------------------------------------------------*/
static Void local noOverloading(bs) /* Type restricted binding group */
List bs; {
List savePreds = preds;
Cell v;
Int line;
hd(depends) = NODEPENDS; /* No need for dependents here */
preds = NIL;
mapProc(restrictedBindAss,bs); /* add assumptions for vars in bs */
mapProc(typeBind,bs); /* type check each binding */
clearMarks(); /* mark fixed variables */
mapProc(markAssumList,tl(defnBounds));
mapProc(markAssumList,tl(varsBounds));
mapProc(markPred,preds);
if (isVar(v=fst(hd(bs))))
line = rhsLine(snd(hd(snd(snd(hd(bs))))));
else {
line = rhsLine(snd(snd(snd(hd(bs)))));
v = hd(v);
}
savePreds = elimConstPreds(line,"binding group",v,savePreds);
preds = appendOnto(preds,savePreds);
map2Proc(generaliseBind,0,NIL,bs); /* Generalise types of defined vars */
}
static Void local restrictedBindAss(b) /* make assums for vars in binding */
Cell b; { /* gp with restricted overloading */
if (isVar(fst(b))) /* function-binding? */
restrictedAss(intOf(rhsLine(snd(hd(snd(snd(b)))))),
fst(b),
fst(snd(b)));
else { /* pattern-binding? */
List vs = fst(b);
List ts = fst(snd(b));
Int line = rhsLine(snd(snd(b)));
for (; nonNull(vs); vs=tl(vs))
if (nonNull(ts)) {
restrictedAss(line,hd(vs),hd(ts));
ts = tl(ts);
}
else
restrictedAss(line,hd(vs),NIL);
}
}
static Void local restrictedAss(l,v,t) /* Assume that type of binding var v*/
Int l; /* is t (if nonNull) in restricted */
Cell v; /* binding group */
Type t; {
newDefnBind(v,t);
if (nonNull(predsAre)) {
ERROR(l) "Explicit overloaded type for \"%s\"",textToStr(textOf(v))
ETHEN
ERRTEXT " not permitted in restricted binding"
EEND;
}
}
/* --------------------------------------------------------------------------
* Type unrestricted binding group with explicitly declared types:
* ------------------------------------------------------------------------*/
static Void local explicitTyping(bs)
List bs; {
static String expBinds = "binding group";
List savePreds = preds;
List evidParams = NIL;
List locPreds = NIL;
List locDeps = NIL;
List bs1;
List lps;
List eps;
Int ng;
preds = NIL;
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) { /* Add assumptions about */
Cell b = hd(bs1); /* each bound var -- can */
newDefnBind(fst(b),fst(snd(b))); /* assume function binding */
if (nonNull(typeIs))
evidParams = cons(makeEvidArgs(predsAre,typeOff),evidParams);
}
evidParams = rev(evidParams);
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) /* Type implicitly-typed */
if (isNull(fst(snd(hd(bs1))))) /* function bindings */
typeBind(hd(bs1));
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) /* Type explicitly-typed */
if (nonNull(fst(snd(hd(bs1))))) { /* binding and save local */
typeBind(hd(bs1)); /* dependents and preds */
locPreds = cons(preds,locPreds);
locDeps = cons(hd(depends),locDeps);
preds = NIL;
hd(depends) = NIL;
}
locPreds = rev(locPreds);
locDeps = rev(locDeps);
/* ----------------------------------------------------------------------
* At this point:
*
* bs = group of bindings being typechecked
* evidParams = list of explicit evidence parameters used in each
* explicitly typed binding in bs, arranged in the order
* that the explicitly typed bindings appear in bs.
* The first element of evidParams is also used as the
* explicit evidence parameters for any implicitly typed
* bindings in the group.
* locPreds = list of predicates required in the body of each
* explicitly typed binding in bs (arranged in the same
* order as evidParams. Once again, the first element of
* locPreds also includes the predicates for the implicitly
* typed bindings in bs.
* locDeps = list of immediate dependents of each binding within the
* binding group bs. Each of these variables must be
* overwritten with an expression in which the variable is
* applied to appropriate evidence parameters, as reqd by
* the corresponding element of evidParams.
* --------------------------------------------------------------------*/
clearMarks(); /* Mark fixed variables */
mapProc(markAssumList,tl(defnBounds));
mapProc(markAssumList,tl(varsBounds));
mapProc(markPred,savePreds);
bs1 = gotoExplicit(bs);
eps = evidParams;
lps = locPreds;
while (nonNull(eps)) {
Cell b = hd(bs1);
Int line = rhsLine(snd(hd(snd(snd(b)))));
List dps;
preds = hd(lps);
savePreds = elimConstPreds(line,expBinds,fst(b),savePreds);
explicitProve(line,expBinds,fst(b),hd(eps),preds);
for (dps=hd(locDeps); nonNull(dps); dps=tl(dps)) {
Cell f = hd(dps);
Cell fQuals = explPreds(textOf(f),bs,evidParams);
if (nonNull(fQuals))
overwrite(f,
addEvidArgs(line,
expBinds,
fst(b),
hd(eps),
fQuals,
mkVar(textOf(f))));
}
eps = tl(eps);
bs1 = gotoExplicit(tl(bs));
lps = tl(lps);
locDeps = tl(locDeps);
}
eps = evidParams; /* add extra dict params */
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) { /* to each binding in bs */
Cell b = hd(bs1);
if (nonNull(fst(snd(b)))) {
qualifyBinding(hd(eps),b);
eps = tl(eps);
}
else
qualifyBinding(hd(evidParams),b);
}
resetGenericsFrom(0); /* Infer typing for each */
eps = copyPreds(hd(evidParams)); /* binding .... */
ng = nextGeneric;
for (bs1=bs; nonNull(bs1); bs1=tl(bs1)) /* Start with implicitly */
if (isNull(fst(snd(hd(bs1))))) /* typed bindings */
generaliseBind(ng,eps,hd(bs1));
bs1 = gotoExplicit(bs); /* Then first explicitly */
generaliseBind(ng,eps,hd(bs1)); /* typed binding */
while (nonNull(bs1=gotoExplicit(tl(bs1)))) {/* followed by remaining */
evidParams = tl(evidParams); /* explicitly typed bndings*/
resetGenericsFrom(0);
eps = copyPreds(hd(evidParams));
ng = nextGeneric;
generaliseBind(ng,eps,hd(bs1));
}
preds = savePreds; /* restore saved predicates*/
}
static List local gotoExplicit(bs) /* skip through list of bindings */
List bs; { /* upto first explicit binding */
while (nonNull(bs) && isNull(fst(snd(hd(bs)))))
bs = tl(bs);
return bs;
}
static List local explPreds(t,bs,locps) /* look up explicit preds for t in */
Text t; /* bindings bs with locps listing */
List bs; /* explicit type preds, implicit */
List locps; { /* included in hd(locps) */
List lps = locps;
for (; nonNull(bs); bs=tl(bs)) {
Cell b = hd(bs);
if (textOf(fst(b))==t)
if (isNull(fst(snd(b))))
return hd(locps);
else
return hd(lps);
if (nonNull(fst(snd(b))))
lps = tl(lps);
}
internal("explPreds");
return NIL; /*NOTREACHED*/
}
/* --------------------------------------------------------------------------
* Type unrestricted binding group with no explicitly declared types:
* ------------------------------------------------------------------------*/
static Void local implicitTyping(bs)
List bs; {
static String impBinds = "implicitly typed binding group";
Int line = rhsLine(snd(hd(snd(snd(hd(bs))))));
Int ng;
List qs;
List savePreds = preds; /* Save and clear preds */
preds = NIL;
#define addImplicit(b) newDefnBind(fst(b),NIL) /* Add assumption for each */
mapProc(addImplicit,bs); /* variable defined in bs */
#undef addImplicit
mapProc(typeBind,bs); /* Type check each binding */
clearMarks(); /* Mark fixed variables */
mapProc(markAssumList,tl(defnBounds));
mapProc(markAssumList,tl(varsBounds));
mapProc(markPred,savePreds);
savePreds = elimConstPreds(line,
impBinds,
fst(hd(bs)),
savePreds); /* remove (loc) const preds*/
preds = simplify(preds); /* simplify remaining preds*/
if (nonNull(preds)) {
map1Proc(addEvidParams,preds,hd(depends));
map1Proc(qualifyBinding,preds,bs);
}
resetGenericsFrom(0);
qs = copyPreds(preds);
ng = nextGeneric;
map2Proc(generaliseBind,ng,qs,bs); /* find defn var types */
preds = savePreds; /* restore predicates */
}
static Void local addEvidParams(qs,v) /* overwrite VARID/OPCELL v with */
List qs; /* application of variable to evid. */
Cell v; { /* parameters given by qs */
if (nonNull(qs)) {
Cell nv;
if (!isVar(v))
internal("addEvidParams");
for (nv=mkVar(textOf(v)); nonNull(tl(qs)); qs=tl(qs))
nv = ap(nv,thd3(hd(qs)));
fst(v) = nv;
snd(v) = thd3(hd(qs));
}
}
/* --------------------------------------------------------------------------
* Type check bodies of class and instance declarations:
* ------------------------------------------------------------------------*/
static Cell dictVar; /* dict var used in inst/class defs*/
static Void local typeInstDefn(in) /* type check implementations of */
Inst in; { /* member functions for instance in*/
typeMembers("instance member binding",
class(inst(in).cl).members,
inst(in).implements,
inst(in).head,
inst(in).freedom);
}
static Void local typeClassDefn(c) /* type check implementations of */
Class c; { /* defaults for class c */
typeMembers("default member binding",
class(c).members,
class(c).defaults,
class(c).head,
class(c).arity);
}
static Void local typeMembers(wh,ms,is,pi,ar)/* type check implementations */
String wh; /* `is' of members `ms' in */
List ms; /* class at instance `t' where*/
List is; /* arity = #vars in t */
Cell pi;
Int ar; {
while (nonNull(is)) {
if (isName(hd(is)))
typeMember(wh,hd(ms),hd(is),pi,ar);
is = tl(is);
ms = tl(ms);
}
}
static Void local typeMember(wh,m,i,pi,ar) /* type check implementation i*/
String wh; /* of member m at instance t */
Name m; /* where arity = #vars in t */
Name i;
Cell pi;
Int ar; {
Int line = rhsLine(snd(hd(name(i).defn)));
Int alpha;
Type rt = NIL; /* required type */
Type it = NIL; /* inferred type */
List evid; /* evidence assignment */
List qs; /* predicate list */
emptySubstitution();
hd(defnBounds) = NIL;
hd(depends) = NODEPENDS;
preds = NIL;
alpha = newTyvars(1+ar);
instantiate(name(m).type);
bind(alpha,typeIs,typeOff);
if (isNull(predsAre) || !oneWayMatches(hd(predsAre),typeOff,pi,alpha+1))
internal("typeMember1");
evid = singleton(triple(hd(predsAre),mkInt(typeOff),dictVar));
resetGenericsFrom(0); /* Set required type, rt */
qs = copyPreds(evid);
rt = generalise(qs,copyTyvar(alpha));
map2Proc(typeDefAlt,alpha,m,name(i).defn); /* Type each alt in defn */
if (nonNull(elimConstPreds(line,wh,m,NIL))) /* need to resolve constant*/
internal("typeMember2"); /* overloading - shouldn't */
/* be any locally constant */
/* overloading at all! */
explicitProve(line,wh,m,evid,preds); /* resolve remaining preds */
resetGenericsFrom(0); /* Determine inferred type */
qs = copyPreds(evid);
it = generalise(qs,copyTyvar(alpha));
if (!equalSchemes(rt,it)) /* check inferred type ok */
tooGeneral(line,m,rt,it);
map1Proc(qualify,evid,name(i).defn); /* add dictionary parameter*/
overDefns = cons(i,overDefns);
}
/* --------------------------------------------------------------------------
* Type check bodies of bindings:
* ------------------------------------------------------------------------*/
static Void local typeBind(b) /* Type check binding */
Cell b; {
if (isVar(fst(b))) { /* function binding */
Cell ass = findTopBinding(fst(b));
Int beta;
if (isNull(ass) || !isInt(snd(ass)))
internal("typeBind");
beta = intOf(snd(ass));
map2Proc(typeDefAlt,beta,fst(b),snd(snd(b)));
}
else { /* pattern binding */
static String lhsPat = "lhs pattern";
static String rhs = "right hand side";
Int beta = newTyvars(1);
Pair pb = snd(snd(b));
Int l = rhsLine(snd(pb));
check(l,fst(pb),NIL,lhsPat,var,beta);
snd(pb) = typeRhs(snd(pb));
shouldBe(l,rhsExpr(snd(pb)),NIL,rhs,var,beta);
}
}
static Void local typeDefAlt(beta,v,a) /* type check alt in func. binding */
Int beta;
Cell v;
Pair a; {
static String valDef = "function binding";
Int l = rhsLine(snd(a));
typeAlt(a);
shouldBe(l,v,NIL,valDef,var,beta);
}
static Cell local typeRhs(e) /* check type of rhs of definition */
Cell e; {
switch (whatIs(e)) {
case GUARDED : { Int beta = newTyvars(1);
map1Proc(guardedType,beta,snd(e));
tyvarType(beta);
}
break;
case LETREC : enterBindings();
mapProc(typeBindings,fst(snd(e)));
snd(snd(e)) = typeRhs(snd(snd(e)));
leaveBindings();
break;
default : snd(e) = typeExpr(intOf(fst(e)),snd(e));
break;
}
return e;
}
static Void local guardedType(beta,gded)/* check type of guard (li,(gd,ex))*/
Int beta; /* should have gd :: Bool, */
Cell gded; { /* ex :: (var,beta) */
static String guarded = "guarded expression";
static String guard = "guard";
Int line = intOf(fst(gded));
gded = snd(gded);
check(line,fst(gded),NIL,guard,typeBool,0);
check(line,snd(gded),NIL,guarded,var,beta);
}
Cell rhsExpr(rhs) /* find first expression on a rhs */
Cell rhs; {
switch (whatIs(rhs)) {
case GUARDED : return snd(snd(hd(snd(rhs))));
case LETREC : return rhsExpr(snd(snd(rhs)));
default : return snd(rhs);
}
}
Int rhsLine(rhs) /* find line number associated with */
Cell rhs; { /* a right hand side */
switch (whatIs(rhs)) {
case GUARDED : return intOf(fst(hd(snd(rhs))));
case LETREC : return rhsLine(snd(snd(rhs)));
default : return intOf(fst(rhs));
}
}
/* --------------------------------------------------------------------------
* Calculate generalisation of types:
* ------------------------------------------------------------------------*/
static Void local generaliseBind(ng,qs,b)
Int ng; /* generalise the types of each var */
List qs; /* defined in binding, qualifying */
Cell b; { /* with predicates in qs */
if (isVar(fst(b))) /* Assumes fixed vars already marked*/
generaliseAss(ng,qs,fst(b)); /* with first ng generics used in qs*/
else {
map2Proc(generaliseAss,ng,qs,fst(b));
}
}
static Void local generaliseAss(ng,qs,v)/* Lookup type of var v in current */
Int ng; /* top level assumptions and replace*/
List qs; /* by its generalisation, qualified */
Cell v; { /* by qs, first ng generics already */
List ass = findTopBinding(v); /* used. */
if (isNull(ass) || !isInt(snd(ass)))
internal("generaliseAss");
resetGenericsFrom(ng);
snd(ass) = generalise(qs,copyTyvar(intOf(snd(ass))));
}
static Type local generalise(qs,t) /* calculate generalisation of t */
List qs; /* having already marked fixed vars*/
Type t; { /* with qualifying preds qs */
if (nonNull(qs))
t = ap(QUAL,pair(qs,t));
if (nextGeneric>0)
t = pair(mkInt(nextGeneric),t);
return t;
}
/* --------------------------------------------------------------------------
* Compare declared type schemes with inferred type schemes:
* ------------------------------------------------------------------------*/
static Void local checkBindSigs(b) /* check explicit type signature in */
Cell b; { /* binding with inferred type */
if (nonNull(fst(snd(b)))) {
if (isVar(fst(b))) /* function-binding? */
checkTypeSig(rhsLine(snd(hd(snd(snd(b))))),
fst(b),
fst(snd(b)));
else { /* pattern-binding? */
List vs = fst(b);
List ts = fst(snd(b));
Int line = rhsLine(snd(snd(b)));
while (nonNull(vs) && nonNull(ts)) {
if (nonNull(hd(ts)))
checkTypeSig(line,hd(vs),hd(ts));
vs = tl(vs);
ts = tl(ts);
}
}
}
}
static Void local checkTypeSig(l,v,t) /* Compare explicit type scheme t */
Int l; /* declared for v with generalised */
Cell v; /* type in current assumption */
Type t; {
Cell ass = findTopBinding(v);
if (isNull(ass))
internal("checkTypeSig");
if (nonNull(t) && !equalSchemes(t,snd(ass)))
tooGeneral(l,v,t,snd(ass));
}
static Void local tooGeneral(l,e,dt,it) /* explicit type sig. too general */
Int l;
Cell e;
Type dt, it; {
ERROR(l) "Declared type too general" ETHEN
ERRTEXT "\n*** Expression : " ETHEN ERREXPR(e);
ERRTEXT "\n*** Declared type : " ETHEN ERRTYPE(dt);
ERRTEXT "\n*** Inferred type : " ETHEN ERRTYPE(it);
ERRTEXT "\n"
EEND;
}
/* --------------------------------------------------------------------------
* Compare type schemes:
* ------------------------------------------------------------------------*/
static Bool local equalSchemes(s1,s2) /* Compare type schemes for equality*/
Type s1, s2; {
Bool b1 = isPolyType(s1);
Bool b2 = isPolyType(s2);
if (b1 || b2) {
if (b1 && b2 && intOf(fst(s1))==intOf(fst(s2))) {
s1 = snd(s1);
s2 = snd(s2);
}
else
return FALSE;
}
b1 = (whatIs(s1)==QUAL);
b2 = (whatIs(s2)==QUAL);
if (b1 && b2 && equalQuals(fst(snd(s1)),fst(snd(s2)))) {
s1 = snd(snd(s1));
s2 = snd(snd(s2));
}
else if (b1 && !b2 && isNull(fst(snd(s1)))) /* maybe somebody gave an */
s1 = snd(snd(s1)); /* explicitly null context? */
else if (!b1 && b2 && isNull(fst(snd(s2))))
s2 = snd(snd(s2));
else if (b1 || b2)
return FALSE;
return equalTypes(s1,s2);
}
static Bool local equalQuals(qs1,qs2) /* Compare lists of qualifying preds*/
List qs1, qs2; {
while (nonNull(qs1) && nonNull(qs2)) { /* loop thru lists */
Cell q1 = hd(qs1);
Cell q2 = hd(qs2);
while (isAp(q1) && isAp(q2)) { /* loop thru args */
if (!equalTypes(arg(q1),arg(q2)))
return FALSE;
q1 = fun(q1);
q2 = fun(q2);
}
if (q1!=q2) /* compare classes */
return FALSE;
qs1 = tl(qs1);
qs2 = tl(qs2);
}
return isNull(qs1) && isNull(qs2); /* compare lengths */
}
static Bool local equalTypes(t1,t2) /* Compare simple types for equality*/
Type t1, t2; {
et: if (whatIs(t1)!=whatIs(t2))
return FALSE;
switch (whatIs(t1)) {
case TYCON :
case OFFSET :
case TUPLE : return t1==t2;
case INTCELL : return intOf(t1)!=intOf(t2);
case UNIT :
case ARROW :
case LIST : return TRUE;
case AP : if (equalTypes(fun(t1),fun(t2))) {
t1 = arg(t1);
t2 = arg(t2);
goto et;
}
return FALSE;
default : internal("equalTypes");
}
return TRUE;/*NOTREACHED*/
}
/* --------------------------------------------------------------------------
* Entry points to type checker:
* ------------------------------------------------------------------------*/
Type typeCheckExp() { /* Type check top level expression */
Type type;
List qs;
typeChecker(RESET);
enterBindings();
inputExpr = typeExpr(0,inputExpr);
clearMarks();
type = copyType(typeIs,typeOff);
if (nonNull(elimConstPreds(0,"expression",inputExpr,NIL)))
internal("typeCheckExp");
preds = simplify(preds);
qs = copyPreds(preds);
type = generalise(qs,type);
if (nonNull(preds)) { /* qualify input expression with */
if (whatIs(inputExpr)!=LAMBDA) /* additional dictionary params */
inputExpr = ap(LAMBDA,pair(NIL,pair(mkInt(0),inputExpr)));
qualify(preds,snd(inputExpr));
}
typeChecker(RESET);
return type;
}
Void typeCheckDefns() { /* Type check top level bindings */
Target t = length(valDefns) + length(instDefns) + length(classDefns);
Target i = 0;
List gs;
typeChecker(RESET);
enterBindings();
setGoal("Type checking",t);
for (gs=valDefns; nonNull(gs); gs=tl(gs)) {
typeDefnGroup(hd(gs));
soFar(i++);
}
for (gs=instDefns; nonNull(gs); gs=tl(gs)) {
typeInstDefn(hd(gs));
soFar(i++);
}
for (gs=classDefns; nonNull(gs); gs=tl(gs)) {
typeClassDefn(hd(gs));
soFar(i++);
}
typeChecker(RESET);
done();
}
static Void local typeDefnGroup(bs) /* type check group of value defns */
List bs; { /* (one top level scc) */
List as;
emptySubstitution();
hd(defnBounds) = NIL;
preds = NIL;
typeBindings(bs); /* find types for vars in bindings */
if (nonNull(preds)) { /* look for unresolved overloading */
Cell b = hd(bs);
Cell ass;
Int line;
Cell v;
preds = simplify(preds); /* Simplify context first ... */
if (isVar(fst(b))) { /* determine var name & line no. */
v = fst(b);
line = rhsLine(snd(hd(snd(b))));
}
else {
v = hd(fst(b));
line = rhsLine(snd(snd(b)));
}
ass = findInAssumList(textOf(v),hd(varsBounds));
ERROR(line) "Unresolved top-level overloading" ETHEN
ERRTEXT "\n*** Binding : %s", textToStr(textOf(v))
ETHEN
if (nonNull(ass)) {
ERRTEXT "\n*** Inferred type : " ETHEN ERRTYPE(snd(ass));
}
ERRTEXT "\n*** Outstanding context : " ETHEN
ERRCONTEXT(copyPreds(preds));
ERRTEXT "\n"
EEND;
}
for (as=hd(varsBounds); nonNull(as); as=tl(as)) {
Cell a = hd(as); /* add infered types to environment*/
Name n = findName(textOf(fst(a)));
if (isNull(n))
internal("typeDefnGroup");
if (catchAmbigs && isAmbiguous(snd(a)))
ambigError(name(n).line,"inferred type",n,snd(a));
name(n).type = snd(a);
}
hd(varsBounds) = NIL;
}
/* --------------------------------------------------------------------------
* Type checker control:
* ------------------------------------------------------------------------*/
Void typeChecker(what)
Int what; {
Int i;
switch (what) {
case RESET : patternMode = FALSE;
matchMode = FALSE;
predProve = NIL;
instPred = NIL;
instExpr = NIL;
emptySubstitution();
emptyAssumption();
preds = NIL;
break;
case MARK : for (i=0; i<MAXTUPCON; ++i)
mark(tupleConTypes[i]);
for (i=0; i<numTyvars; ++i)
mark(tyvars[i].bound);
mark(typeIs);
mark(predsAre);
mark(defnBounds);
mark(varsBounds);
mark(depends);
mark(preds);
mark(dictVar);
mark(predProve);
mark(instPred);
mark(instExpr);
mark(arrow);
mark(typeList);
mark(typeIntToInt);
mark(predNum);
break;
case INSTALL : typeChecker(RESET);
for (i=0; i<MAXTUPCON; ++i)
tupleConTypes[i] = NIL;
dictVar = inventDictVar();
var = mkOffset(0);
arrow = fn(var,mkOffset(1));
typeList = ap(LIST,var);
nameNil = addPrimCfun("[]",0,0,ap(mkInt(1),
typeList));
nameCons = addPrimCfun(":",2,1,ap(mkInt(1),
fn(var,
fn(typeList,
typeList))));
typeUnit = UNIT;
typeBool = addPrimTycon("Bool",0,0,NIL);
nameFalse = addPrimCfun("False",0,0,typeBool);
nameTrue = addPrimCfun("True",0,1,typeBool);
typeInt = addPrimTycon("Int",0,0,NIL);
typeFloat = addPrimTycon("Float",0,0,NIL);
typeChar = addPrimTycon("Char",0,0,NIL);
typeString = addPrimTycon("String",0,1,ap(LIST,
typeChar));
typeIntToInt = ap(ap(ARROW,typeInt),typeInt);
typeDialogue = newTycon(findText("Dialogue"));
nameFromInt = newName(findText("fromInteger"));
classNum = newClass(findText("Num"));
tycon(typeDialogue).defn = PREDEFINED;
name(nameFromInt).defn = PREDEFINED;
class(classNum).head = PREDEFINED;
predNum = ap(classNum,var);
break;
}
}
/*-------------------------------------------------------------------------*/